昨天連滾帶爬的走出了 interrupt的泥淖,希望之後能夠有空把他弄得更清楚,今天要講的東西是下半部的 interrupt處理。
softirq 對應hardirq,只是softirq是純軟體的處理。目前softirq的數量已經固定了,並不會有其他增加,底下是在linux的註釋,表示幾乎所有想做的行為都可以利用tasklet完成,請避免增加新的softirq。
PLEASE, avoid to allocate new softirqs, if you need not really high
frequency threaded job scheduling. For almost all the purposes
tasklets are more than enough. F.e. all serial device BHs et
al. should be converted to tasklets, not to softirqs.
以下是在程式碼中利用枚舉靜態聲明softirq
enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
IRQ_POLL_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the
numbering. Sigh! */
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
};
HI_SOFTIRQ=0
: 優先級最高的softirqTIMER_SOFTIRQ
: 用於計時器的softirqNET_TX_SOFTIRQ
: 發送網路封包的softirqNET_RX_SOFTIRQ
: 接收網路封包的softirqBLOCK_SOFTIRQ
: 用於block device的softirqIRQ_POLL_SOFTIRQ
: 用於block device的softirqTASKLET_SOFTIRQ
: 專門給 tasklet 調用的softirqSCHED_SOFTIRQ
: 用在排程與負載平衡HRTIMER_SOFTIRQ
: 高精度的計時器RCU_SOFTIRQ
: 服務RCU的softirq
NR_SOFTIRQS
利用軟中斷實現的下半部中斷處理機制,在linux可以看見 tasklet_struct
的結構,在稍後會看見。
tasklet 有幾個性質
tasklet_schedule()
函數之後,tasklet至少會在某個CPU上執行一次struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
next
:多個tasklet可以組成鏈表,指向下一個taskletstate
: TASKLET_STATE_SCHED
表示tasklet已經被排程,TASKLET_STATE_RUN
代表tasklet正在運行。count
: 若不為0代表該tasklet不允許執行。func
:代表tasklet的處理程序。data
:傳遞參數給tasklet。
利用open_softirq
可以註冊一個softirq, 利用 raise_softirq
可以主動觸發softirq
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
void raise_softirq(unsigned int nr)
{
unsigned long flags;
local_irq_save(flags);
raise_softirq_irqoff(nr);
local_irq_restore(flags);
}
工作佇列(work queue)是另外一種將工作推後執行的形式,它和前面討論的tasklet有所不同。工作佇列可以把工作推後,交由一個核心執行緒去執行,也就是說,這個下半部分可以在程序上下文中執行。這樣,通過工作佇列執行的程式碼能佔盡程序上下文的所有優勢。最重要的就是工作佇列允許被重新排程甚至是睡眠。